﻿// ActionScript file
/**
* 提供对sound.swf的控制，包括加载、开关等
* 
* @Expand:
* 1、提供uid的检查 (Resloved)
* 2、加载多个url及其加载控制
*/
package org.nickro.project.sound{
	import flash.errors.IOError;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.media.Sound;
	import flash.media.SoundChannel;
	import flash.media.SoundTransform;
	import flash.net.URLRequest;
	import flash.utils.Dictionary;
	
	import org.nickro.project.events.LoadEvent;
	import org.nickro.externallibrary.tween.TweenLite;
	import org.nickro.project.debug.Console;
	
	public class SoundManager extends EventDispatcher
	{
		private var _sounds:Array = [];
		private var _soundsDict:Dictionary;
		
		private static var instance:SoundManager;
		
		private var _url:String;
		public function SoundManager(singleton:SingletonEnforcer)
		{
			_soundsDict = new Dictionary(true);
		}
		
		public static function getInstance():SoundManager
		{
			if(SoundManager.instance == null)
			{
				SoundManager.instance = new SoundManager(new SingletonEnforcer());
			}
			return SoundManager.instance;
		}
		
		public function addExternalSound(url:String,uid:String,bufferTime:Number = 1000,checkPolicyFile:Boolean = false):Boolean
		{
			_url = url;
			for(var i:int = 0;i < _sounds.length ; i++)
			{
				if(_sounds[i].uid == uid)
				{
					return (false);
					throw new Error(uid + "has been used!plz change another uid.");
					Console.error('Debug [SoundManager] Error :: ' + uid + "has been used!plz change another uid.");
				}
			}
			var sound:Sound = new Sound(null,null);
			try
			{
				sound.load(new URLRequest(url));
			}catch (e:Error)
			{
				throw new Error("sound" + url + "can't load");
			}
			sound.addEventListener(ProgressEvent.PROGRESS,onProgress);
			sound.addEventListener(Event.COMPLETE,onComplete);
			sound.addEventListener(IOErrorEvent.IO_ERROR,onIOError);
			
			var obj:Object = { };
			obj.url = url;
			obj.uid = uid;
			obj.sound = sound;
			obj.channel = new SoundChannel();
			obj.position = 0;
			obj.paused = 0;
			obj.volume = 1;
			obj.startTime = 0;
			obj.loops = 0;
			obj.pausedByAll = false;
			_soundsDict[uid] = obj;
			_sounds.push(obj);
			return (true);
		}
		
		public function addLibrarySound(className:*,uid:String):Boolean
		{
			for(var i:int = 0;i<_sounds.length ; i++)
			{
				if(_sounds[i].uid == uid)
				{
					return (false);
					throw new Error(uid + "has been used!plz change another uid.");
				}
			}
			var sound:Sound = new (className) as Sound;
			var obj:Object = { };
			obj.url = "libraySoundClass : " + className;
			obj.uid = uid;
			obj.sound = sound;
			obj.channel = new SoundChannel();
			obj.position = 0;
			obj.paused = 0;
			obj.volume = 1;
			obj.startTime = 0;
			obj.loops = 0;
			obj.pausedByAll = false;
			_soundsDict[uid] = obj;
			_sounds.push(sound);
			return (true);
		}
		
		public function addSound(className:*,uid:String):Boolean
		{
			for(var i:int = 0;i<_sounds.length ; i++)
			{
				if(_sounds[i].uid == uid)
				{
					return (false);
				}
			}
			var sound:Sound = className;
			var obj:Object = { };
			obj.url = "soundClass : " + className;
			obj.uid = uid;
			obj.sound = sound;
			obj.channel = new SoundChannel();
			obj.position = 0;
			obj.paused = 0;
			obj.volume = 1;
			obj.startTime = 0;
			obj.loops = 0;
			obj.pausedByAll = false;
			_soundsDict[uid] = obj;
			_sounds.push(sound);
			return (true);
		}
		
		public function removeSound(uid:String):void
		{
			for(var i:int = 0 ;i < _sounds.length ;i++)
			{
				if(_sounds[i].uid == uid)
				{
					_sounds[i] = null;
					_sounds[i].splice(i,1);
				}
			}
			delete _soundsDict[uid];
		}
		
		public function removeAllSounds():void
		{
			for(var i:int = 0 ;i < _sounds.length ;i++)
			{
				_sounds[i] = null;
			}
			this._sounds = new Array();
            this._soundsDict = new Dictionary(true);
		}
		
		public function muteAllSounds():void
		{
			var uid:String;
			
			for(var i:int = 0 ;i< _sounds.length ;i++)
			{
				uid = _sounds[i].uid;
				setSoundVolume(uid,0);
			}
		}
		
		
		
		public function playAllSounds(overPause:Boolean = false):void
		{
			var uid:String;
			for(var i:int = 0;i<_sounds.length;i++)
			{
				uid = _sounds[i].uid;
				if(overPause)
				{
					if(_soundsDict[uid].pausedByAll)
					{
						_soundsDict[uid].pausedByAll = false;
						playSound(uid);
					}
				}else
				{
					playSound(uid);
				}
			}
		}
		
		public function pauseAllSounds(overPause:Boolean = true):void
		{
			var uid:String;
			for(var i:int = 0; i< _sounds.length ; i++)
			{
				uid = _sounds[i].uid;
				if(overPause)
				{
					if(!_soundsDict[uid].paused)
					{
						_soundsDict[uid].pausedByAll = true;
						pauseSound(uid);
					}
				}else
				{
					pauseSound(uid);
				}
			}
		}
		
		public function stopAllSounds(overPause:Boolean = true):void
		{
			var uid:String;
			for(var i:int = 0; i< _sounds.length ;i++)
			{
				uid = _sounds[i].uid;
				if(overPause)
				{
					if(!_soundsDict[uid].paused)
					{
						_soundsDict[uid].pausedByAll = true;
						stopSound(uid);
					}
				}else
				{
					stopSound(uid);
				}
			}
		}
		
		public function playSound(uid:String,volume:Number = 1,startTime:Number = 0,loops:int = 0):void
		{
			if (_soundsDict[uid]) {
				var obj:Object = _soundsDict[uid];
				obj.volume = volume;
				obj.startTime = startTime;
				obj.loops = loops;
				if(obj.paused)
				{
					obj.channel = Sound(obj.sound).play(obj.position,obj.loops,new SoundTransform(obj.volume));
				}else
				{
					obj.channel = Sound(obj.sound).play(startTime,obj.loops,new SoundTransform(obj.volume));
				}
				obj.paused = false;
			}else {
				throw new Error("Sound ID [ " + uid + " ] isn't exist");
			}
			
		}
		
		public function pauseSound(uid:String):void
		{
			if (_soundsDict[uid]) {
				var obj:Object = _soundsDict[uid];
				obj.paused = true;
				obj.position = obj.channel.position;
				//音乐播放完成后，暂停音乐特殊处理.
				if (obj.position == obj.sound.length) {
					obj.paused = false;
					obj.position = 0;
				}
				obj.channel.stop();
			}else {
				throw new Error("Sound ID [ " + uid + " ] isn't exist");
			}
			
		}
		
		public function fadeSound(uid:String,completeHandler:Function = null,targetVolume:int = 0,time:int = 1):void
		{
			var sc:SoundChannel = _soundsDict[uid].channel;
			TweenLite.to(sc,time,{volume:targetVolume,onComplete:completeHandler});
		}
		//停止，重新开始播放,如播放器的圆形按钮
		public function stopSound(uid:String):void
		{
			var obj:Object = _soundsDict[uid];
			obj.paused = false;
			obj.position = 0;
			obj.channel.stop();
		}
		
		public function setSoundVolume(uid:String,vol:Number):void
		{
			var obj:Object = _soundsDict[uid];
			var sts:SoundTransform = obj.channel.soundTransform;
			sts.volume = vol;
			obj.channel.soundTransform = sts;
			obj.volume = vol;
		}
		public function getSoundVolume(uid:String):Number
		{
			return _soundsDict[uid].volume;
		}
		
		public function getSoundPosition(uid:String):Number
		{
			return _soundsDict[uid].position;
		}
		
		public function getSoundDuration(uid:String):Number
		{
			return _soundsDict[uid].sound.length;
		}
		
		public function getSoundObject(uid:String):Number
		{
			return _soundsDict[uid].sound;
		}
		
		public function get sounds():Array
		{
			return _sounds;
		}
		
		private function onProgress(e:ProgressEvent):void
		{
			//var percent : int = int(e.bytesLoaded/e.bytesTotal * 100);
			//dispatchEvent(new LoadEvent(LoadEvent.PROGRESS,percent);
		}
		private function onComplete(e:Event):void
		{
			dispatchEvent(new LoadEvent(LoadEvent.COMPLETE, null));
		}
		private function onIOError(e:IOErrorEvent):void
		{
			throw new IOError('"' + _url + '"'+ "isn't existed or path isn't true");
		}
	}
}
class SingletonEnforcer {}